package com.jsyso.jsyso.db;

import org.apache.commons.lang3.StringUtils;

/**
 * 分页
 * @author janjan, xujian_jason@163.com
 *
 */
public class Page {
	/* 模板可用变量 */
	// 总记录数
	public static final String VAR_TOTALSIZE 	= "{totalSize}";
	// 总页数
	public static final String VAR_PAGECOUNT 	= "{pageCount}";
	// 当前页码
	public static final String VAR_PAGENO 		= "{pageNo}";
	// 每页记录数
	public static final String VAR_PAGESIZE 	= "{pageSize}";
	// 链接点击js函数（如果为空则输出：javascript:;）
	public static final String VAR_FUNCNAME 	= "{funcName}";
	// item循环页码
	public static final String VAR_ITEM_I 		= "{i}";
	// item循环当前选择项
	public static final String VAR_ITEM_ACTIVE 	= "{active}";
	
	// 每页显示条数（默认：20条）
	private int pageSize 		= 20;
	// 数据总条数
	private long totalSize 		= 0;
	// 当前选中的页（默认：第一页）
	private int pageNo 			= 1;
	// 每次显示的页数（默认：显示8页）
	private int listPage 		= 8;
	// 分页模板（[0]=begin、[1]=item、[2]=end）
	private String[] templates 	= new String[3];
	// 设置点击页码调用的js函数名称，默认为page，在一页有多个分页对象时使用。
	private String funcName 	= "page";
	// 函数的附加参数，第三个参数值。
	private String funcParam 	= "{}";
	// 当前页码的CSS样式名称，默认为"active"
	private String activeClass 	= " active";
	
	// 首页HTML代码，默认为：«
	private String firstCode 	= "&laquo;";
	// 上一页HTML代码，默认为：‹
	private String prevCode 	= "&lsaquo;";
	// 下一页HTML代码，默认为：›
	private String nextCode 	= "&rsaquo;";
	// 末页HTML代码，默认为：»
	private String lastCode 	= "&raquo;";
	
	// 首页索引
	private int first 			= 1;
	// 尾页索引
	private int last 			= 1;
	// 上一页索引
	private int prev 			= 1;
	// 下一页索引
	private int next 			= 1;
	
	/**
	 * 创建page
	 * @param pageNo 当前页码
	 * @param totalSize 数据总条数
	 * @return
	 */
	public static Page create(int pageNo, long totalSize) {
		return new Page(pageNo, totalSize);
	}
	
	public Page() {
		this(1, 0, 20);
	}
	
	public Page(int pageNo, long totalSize) {
		this(pageNo, totalSize, 20);
	}
	
	public Page(int pageNo, long totalSize, int pageSize) {
		this.pageNo = pageNo;
		this.totalSize = totalSize;
		this.pageSize = pageSize;
	}
	
	public Page setTplBegin(String tpl) {
		templates[0] = tpl;
		return this;
	}
	
	public Page setTplItem(String tpl) {
		templates[1] = tpl;
		return this;
	}
	
	public Page setTplEnd(String tpl) {
		templates[2] = tpl;
		return this;
	}
	
	public Page setFuncName(String funcName) {
		this.funcName = funcName;
		return this;
	}
	
	public Page setFuncParam(String funcParam) {
		this.funcParam = funcParam;
		return this;
	}

	public Page setActiveClass(String activeClass) {
		this.activeClass = activeClass;
		return this;
	}
	
	public void setTotalSize(int totalSize) {
		this.totalSize = totalSize;
	}
	
	public void setPageNo(int pageNo) {
		this.pageNo = pageNo;
	}
	
	public void setListPage(int listPage) {
		this.listPage = listPage;
	}
	
	public void setFirstCode(String firstCode) {
		this.firstCode = firstCode;
	}
	
	public void setPrevCode(String prevCode) {
		this.prevCode = prevCode;
	}
	
	public void setNextCode(String nextCode) {
		this.nextCode = nextCode;
	}
	
	public void setLastCode(String lastCode) {
		this.lastCode = lastCode;
	}
	
	/**
	 * 初始化数据
	 */
	protected void initialize() {
		this.first = 1;
		this.last = (int)Math.ceil(this.totalSize / (this.pageSize < 1 ? 20 : this.pageSize));
		if (this.last < this.first) {
			this.last = this.first;
		}
		if (this.pageNo <= 1) {
			this.pageNo = this.first;
		}
		if (this.pageNo >= this.last) {
			this.pageNo = this.last;
		}
		if (this.pageNo < this.last - 1) {
			this.next = this.pageNo + 1;
		} else {
			this.next = this.last;
		}
		if (this.pageNo > 1) {
			this.prev = this.pageNo - 1;
		} else {
			this.prev = this.first;
		}
		if (this.pageNo < this.first) { 
			this.pageNo = this.first;
		}
		if (this.pageNo > this.last) { 
			this.pageNo = this.last;
		}
	}
	
	/**
	 * 显示分页
	 */
	public String show() {
		// 初始化
		this.initialize();
		String innerPageNoTpl = "{{prevOrNextNo}}";
		// begin模板
		StringBuilder sb = new StringBuilder(this.templateVarReplace(0));
		// 计算前后显示item
		int end =  pageNo + (listPage / 2);
		int begin = pageNo - (listPage / 2);
		if (begin < first) {
			end -= begin;
			begin = first;
		}
		if (end > last) {
			begin -= end - last;
			if(begin < this.first) {
				begin = this.first;
			}
			end = last;
		}
		// 首页
		if(begin > this.first) {
			sb.append(StringUtils.replaceEach(this.templateVarReplace(1), new String[]{
					VAR_ITEM_ACTIVE, VAR_ITEM_I, innerPageNoTpl
			}, new String[]{
					StringUtils.EMPTY, this.firstCode, String.valueOf(this.first)
			}));
		}
		// 上一页
		if(this.pageNo > this.first) {
			sb.append(StringUtils.replaceEach(this.templateVarReplace(1), new String[]{
					VAR_ITEM_ACTIVE, VAR_ITEM_I, innerPageNoTpl
			}, new String[]{
					StringUtils.EMPTY, this.prevCode, String.valueOf(this.prev)
			}));
		}
		// item模板
		for (int i=begin; i<=end; ++i) {
			sb.append(StringUtils.replaceEach(this.templateVarReplace(1), new String[]{
					VAR_ITEM_ACTIVE, VAR_ITEM_I, innerPageNoTpl
			}, new String[]{
					this.pageNo == i ? this.activeClass : "",
					String.valueOf(i),
					String.valueOf(i)
			}));
		}
		// 下一页
		if(this.pageNo < this.last) {
			sb.append(StringUtils.replaceEach(this.templateVarReplace(1), new String[]{
					VAR_ITEM_ACTIVE, VAR_ITEM_I, innerPageNoTpl
			}, new String[]{
					StringUtils.EMPTY, this.nextCode, String.valueOf(this.next)
			}));
		}
		// 末页
		if(end < this.last) {
			sb.append(StringUtils.replaceEach(this.templateVarReplace(1), new String[]{
					VAR_ITEM_ACTIVE, VAR_ITEM_I, innerPageNoTpl
			}, new String[]{
					StringUtils.EMPTY, this.lastCode, String.valueOf(this.last)
			}));
		}
		// end模板
		return sb.append(this.templateVarReplace(2)).toString();
	}
	
	@Override
	public String toString() {
		return this.show();
	}
	
	/**
	 * 模板变量替换
	 * @param index
	 * @return
	 */
	protected String templateVarReplace(int index) {
		return StringUtils.replaceEach(this.templates[index], new String[]{
				VAR_TOTALSIZE, VAR_PAGECOUNT, VAR_PAGENO,
				VAR_PAGESIZE, VAR_FUNCNAME
		}, new String[]{
			String.valueOf(this.totalSize),
			String.valueOf(this.last),
			String.valueOf(this.pageNo),
			String.valueOf(this.pageSize),
			String.format("%s({{prevOrNextNo}}, %s, %s)", this.funcName, this.pageSize, this.funcParam),
		});
	}
}
